﻿using System;
using System.Linq;
using System.Reflection;
using FluentAssertions;
using LINQPad.OpenAccess.Metadata;
using LINQPad.OpenAccess.Metadata.Reflection;
using LINQPad.OpenAccess.Metadata.Reflection.Adapters;
using LINQPad.OpenAccess.Metadata.Reflection.Locators;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace LINQPad.OpenAccess.Tests.Metadata.Reflection.Locators
{
    /// <summary>
    /// Summary description for ContextTypeLocatorFixture
    /// </summary>
    [TestClass]
    public class ContextTypeLocatorFixture
    {
        private Mock<IContextTypeInfoAdapter> CreateContextTypeInfoAdapterMock( )
        {
            var adapterMock = new Mock<IContextTypeInfoAdapter>( );
            adapterMock.Setup( i => i.Adapt( It.IsAny<Type>( ) ) )
                       .Returns<Type>
                            (
                                ( t ) => this.CreateContextTypeInfoMock( t ).Object
                            );
            return adapterMock;
        }
        private Mock<IContextTypeInfo> CreateContextTypeInfoMock( Type contextType )
        {
            var mock = new Mock<IContextTypeInfo>( );
            mock.SetupGet( p => p.ContextType ).Returns( contextType );
            return mock;
        }

        [TestMethod]
        public void LocatesContextTypesFromTestAssembly( )
        {
            var adapterMock = this.CreateContextTypeInfoAdapterMock( );
            var locator = new ContextTypeLocator( adapterMock.Object, new ReflectionService( ) );

            var contextTypes = locator.GetFromAssembly( Assembly.GetExecutingAssembly( ) );

            contextTypes.Should( )
                        .NotBeNull( );

            var arrContextTypes = contextTypes.ToArray( );

            arrContextTypes.Length.Should( ).Be( 3, "our test assembly contains a fluent, attribute based and xml based context" );

            arrContextTypes.Select( i => i.ContextType )
                           .Should( )
                           .Contain( typeof( TestModel.Fluent.SofiaCarsRental21Model ) )
                           .And.Contain( typeof( TestModel.Fluent.SofiaCarsRental21Model ) )
                           .And.Contain( typeof( TestModel.Fluent.SofiaCarsRental21Model ) );
        }
        [TestMethod]
        public void ReturnsEmptyCollectionIfNoContextTypesAreFound( )
        {
            var adapterMock = this.CreateContextTypeInfoAdapterMock( );
            var locator = new ContextTypeLocator( adapterMock.Object, new ReflectionService( ) );
            var contextTypes = locator.GetFromAssembly( typeof( IQueryable ).Assembly );

            contextTypes.Should( )
                        .NotBeNull( )
                        .And
                        .BeEmpty( );
        }
        [TestMethod]
        public void ThrowsArgumentNullExceptionIfAssemblyIsNull( )
        {
            var adapterMock = this.CreateContextTypeInfoAdapterMock( );
            var locator = new ContextTypeLocator( adapterMock.Object, new ReflectionService( ) );

            locator.Invoking( e => e.GetFromAssembly( null ) )
                   .ShouldThrow<ArgumentNullException>( );
        }
    }
}